package foxesAndRabbits;

import java.util.Random;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.awt.Color;


/**
 * A simple predator-prey simulator, based on a rectangular field containing
 * rabbits and foxes.
 * 
 * @author David J. Barnes and Michael Kolling
 * @editor Marc Bruins, Michel Jansma and Stephan Veenstra
 * @version 1.1
 */
public class Simulator {
	// Constants representing configuration information for the simulation.
	// The default width for the grid.
	private static final int DEFAULT_WIDTH = 50;
	// The default depth of the grid.
	private static final int DEFAULT_DEPTH = 50;
	// The probability that a fox will be created in any given grid position.
	private static final double FOX_CREATION_PROBABILITY = 0.03;
	// The probability that a rabbit will be created in any given grid position.
	private static final double RABBIT_CREATION_PROBABILITY = 0.06;
	// The probability that a Falcon will be created in any given grid position.
	private static final double FALCON_CREATION_PROBABILITY = 0.06;
	// The probability that a Falcon will be created in any given grid position.
	private static final double TOTALHUNTERS = 15;
	
	//
	private static PlaySound bgSound;
	
	public String musicFilePath = "./walk-of-life.mid";

	// List of animals in the field.
	private List<Actor> actors;
	// The current state of the field.
	private Field field;
	// The current step of the simulation.
	private int step;
	// A graphical view of the simulation.
	private SimulatorView view;

	public static void main(String[] args) {
		new Simulator();
	}

	/**
	 * Construct a simulation field with default size.
	 */
	public Simulator() {
		this(DEFAULT_DEPTH, DEFAULT_WIDTH);
	}

	/**
	 * Create a simulation field with the given size.
	 * 
	 * @param depth
	 *            Depth of the field. Must be greater than zero.
	 * @param width
	 *            Width of the field. Must be greater than zero.
	 */
	public Simulator(int depth, int width) {
		if (width <= 0 || depth <= 0) {
			System.out.println("The dimensions must be greater than zero.");
			System.out.println("Using default values.");
			depth = DEFAULT_DEPTH;
			width = DEFAULT_WIDTH;
		}

		actors = new ArrayList<Actor>();
		field = new Field(depth, width);

		// Create a view of the state of each location in the field.
		view = new SimulatorView(depth, width);
		view.setSimulator(this); // Sla simulator instantie op in simulator view
		view.setColor(Rabbit.class, Color.orange);
		view.setColor(Fox.class, Color.blue);
		view.setColor(Falcon.class, Color.gray);
		view.setColor(Hunter.class, Color.black);
		
		
		//Start background sound
		startSound(this.musicFilePath);
		// Setup a valid starting point.
		reset();
		// runLongSimulation();
	}

	/**
	 * Run the simulation from its current state for a reasonably long period,
	 * e.g. 500 steps.
	 */
	public void runLongSimulation() {
		simulate(500);
	}

	/**
	 * Run the simulation from its current state for the given number of steps.
	 * Stop before the given number of steps if it ceases to be viable.
	 * 
	 * @param numSteps
	 *            The number of steps to run for.
	 *            
	 */
	public void simulate(int numSteps) {
		for (int step = 1; step <= numSteps && view.isViable(field); step++) {
			simulateOneStep();
		}
	}

	/**
	 * Run the simulation from its current state for a single step. Iterate over
	 * the whole field updating the state of each fox and rabbit.
	 */
	public void simulateOneStep() {
		step++;
		
		// Provide space for newborn animals.
		List<Actor> newActors = new ArrayList<Actor>();
		// List<Actor> newH = new ArrayList<Actor>();

		// Let all rabbits act.
		for (Iterator<Actor> it = actors.iterator(); it.hasNext();) {
			Actor animal = it.next();
			animal.act(newActors);
			if (!animal.isActive()) {
				it.remove();
			}
		}

		// Add the newly born foxes and rabbits to the main lists.
		actors.addAll(newActors);

		view.showStatus(step, field);
	}

	/**
	 * Reset the simulation to a starting position.
	 */
	public void reset() {
		step = 0;
		actors.clear();
		populateAnimals();
		populateHunters();
		// Show the starting state in the view.
		view.showStatus(step, field);
	}

	/**
	 * Randomly populate the field with foxes and rabbits.
	 */
	private void populateAnimals() {
		Random rand = Randomizer.getRandom();
		field.clear();
		for (int row = 0; row < field.getDepth(); row++) {
			for (int col = 0; col < field.getWidth(); col++) {
				if (rand.nextDouble() <= FOX_CREATION_PROBABILITY) {
					Location location = new Location(row, col);
					Fox fox = new Fox(true, field, location);
					actors.add(fox);
				} else if (rand.nextDouble() <= RABBIT_CREATION_PROBABILITY) {
					Location location = new Location(row, col);
					Rabbit rabbit = new Rabbit(true, field, location);
					actors.add(rabbit);
				} else if (rand.nextDouble() <= FALCON_CREATION_PROBABILITY) {
					Location location = new Location(row, col);
					Falcon falcon = new Falcon(true, field, location);
					actors.add(falcon);
				}
				// else leave the location empty.
			}
		}
	}
	
	/**
	 * Populate hunters.
	 */
	
	private void populateHunters() {
		Random rand = Randomizer.getRandom();
		for (int i = 0; i < TOTALHUNTERS; i++) {
			//GetRandomField
			int x = rand.nextInt(field.getDepth() + 1);
			int y = rand.nextInt(field.getWidth() + 1);
			if (x == 0) {x = x + 1;}
			if (y == 0) {y = y + 1;}
			
			Location location = new Location(x, y);
			Hunter hunter = new Hunter(field, location);
			actors.add(hunter);
		}
	}
	
	public void startSound(String fileSrc){
		bgSound = new PlaySound(fileSrc);
		bgSound.startSound();
	}
	
	public void stopSound(){
		bgSound.stopSound();
	}
	
	
	public void startAutomaticSimulator(){
		System.out.println("FDS");
	}
	
	public void stopAutomaticSimulator(){
		System.out.println("FDS");
	}

}
